package com.wbs.service;

import com.google.common.base.Preconditions;
import com.wbs.dao.SysDeptMapper;
import com.wbs.exception.ParamException;
import com.wbs.model.SysDept;
import com.wbs.param.DeptParam;
import com.wbs.util.BeanValidator;
import com.wbs.util.LevelUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

@Service
public class SysDeptService {

    @Resource
    private SysDeptMapper sysDeptMapper;


    // 新增部门
    public void save(DeptParam param) {

        BeanValidator.check(param);  // 做一个最基本的校验

        if (checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一部门下边存在相同名称的部门");
        }

        SysDept sysDept = SysDept.builder().name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();

        sysDept.setLevel(LevelUtil.calculataLevel(getLevel(param.getParentId()), param.getParentId()));

        sysDept.setOperateIp("127.0.0.1");  // TODO:
        sysDept.setOperateTime(new Date());  // TODO:
        sysDept.setOperator("system"); // TODO:

        // insert 是插入所有的字段，insertSelective 是判断是否为空，然后根据为否为空插入，如果有一些字段没有传入的话就，是不会出让notNull约束的
        sysDeptMapper.insertSelective(sysDept);  // 保存

    }

    public void update(DeptParam param) {

        BeanValidator.check(param);  // 做一个最基本的校验

        if (checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一部门下边存在相同名称的部门");
        }
        SysDept before = sysDeptMapper.selectByPrimaryKey(param.getId());  // 取到更新前的部门
        Preconditions.checkNotNull(before, "待更新的部门不存在");  // 做一个校验，看待更新的部门是否存在

        if (checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一部门下边存在相同名称的部门");
        }
        SysDept after = SysDept.builder().id(param.getId()).name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();
        after.setLevel(LevelUtil.calculataLevel(getLevel(param.getParentId()), param.getParentId()));
        after.setOperateIp("127.0.0.1");  // TODO:
        after.setOperateTime(new Date());  // TODO:
        after.setOperator("system-update"); // TODO:

        updateWithChild(before, after);
    }

    // 加上事务，保证都成功或者都失败
    @Transactional
    public void updateWithChild(SysDept before, SysDept after) {

        // 判断是否需要更新子部门
        String newLevelPrefix = after.getLevel();  // 取出新部门的前缀
        String oldLevelPrefix = before.getLevel();  // 取出新部门的前缀
        if (!newLevelPrefix.equals(oldLevelPrefix)) {
            // 当跟新前后的level不一致的时候，需要做子部门的更新
            List<SysDept> deptList = sysDeptMapper.getChildDeptListByLevel(before.getLevel());  // 取出before对应的子部门
            if (CollectionUtils.isNotEmpty(deptList)) {
                // 子部门不为空需要处理
                for (SysDept dept : deptList) {
                    String level = dept.getLevel();
                    if (level.indexOf(oldLevelPrefix) == 0) {
                        // 如果以oldLevelPrefix开头的话，进行处理
                        // 如果修改的部门下边有部门的话 ，新的level=新的level+旧的level与旧的level的父节点的level不同的一部分
                        // eg:0.1.2的子节点为0.1.2.3，修改0.1.2为0.4.5的时候，需要将0.1.2的子节点0.1.2.3修改为0.4.5.3，0.4.5.3中的.3是oldLevelPrefix中结尾部分，
                        // 下边的level.substring(oldLevelPrefix.length())正好可以满足这样的需求，但是如果0.1.2没有子节点的话，level.substring(oldLevelPrefix.length())
                        // 这句话得到的字符串长度为0，即是0.1.2节点，而不是他下边的子节点的时候，新的level=newLevelPrefix
                        //
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());  // 得到新的level
                        dept.setLevel(level);  // 更新dept中的level

                    }
                }
                sysDeptMapper.batchUpdateDeptLevel(deptList);
            }
        }

        sysDeptMapper.updateByPrimaryKey(after);
    }

    private boolean checkExist(Integer parentId, String deptName, Integer deptId) {
        // 更新的时候，deptId传入的是实际的Id,新增的时候是空值
        // 如果查找到的部门大于0个，说明下边有部门名称相同的
        return sysDeptMapper.countByNameAndParentId(parentId, deptName, deptId) > 0;
    }

    // 根据上级部门的ID获取上级部门的level
    private String getLevel(Integer deptId) {
        SysDept sysDept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (sysDept == null) {
            // 判断上级部门是否为空
            return null;
        }
        return sysDept.getLevel();
    }

}
